package com.xxx.transaction;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

/**
 * Rabbit MQ事务
 *  消费者模式使用事务
	假设消费者模式中使用了事务，并且在消息确认之后进行了事务回滚，那么RabbitMQ会产生什么样的变化？
	结果分为两种情况：
		autoAck=false手动应对的时候是支持事务的，也就是说即使你已经手动确认了消息已经收到了，但在确认消息会等事务的返回解决之后，在做决定是确认消息还是重新放回队列，如果你手动确认现在之后，又回滚了事务，那么已事务回滚为主，此条消息会重新放回队列；
		autoAck=true如果自定确认为true的情况是不支持事务的，也就是说你即使在收到消息之后在回滚事务也是于事无补的，队列已经把消息移除了；
 * 
 * @author guweiqiang
 * 2018年6月13日
 */
public class Consumer {
	
	// 队列名称
	private static final String QUEUE_NAME = "rabbitMQ.transaction";
	
	// rabbit MQ server host
	private static final String HOST = "localhost";

	public static void main(String[] args) throws IOException, TimeoutException {
		// 1.创建连接工厂，并设置工厂相关属性
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost(HOST); // MQ server
		
		// 2.创建一个连接
		Connection connection = factory.newConnection();
		
		// 3.创建一个通道
		Channel channel = connection.createChannel();
		
		// 4.声明一个队列
		channel.queueDeclare(QUEUE_NAME, true, false, false, null);
		// 第一个参数表示队列名称
		// 第二个参数为队列是否持久化（true表示是，队列将在服务器重启时生存）
		// 第三个参数为是否是独占队列（创建者可以使用的私有队列，断开后自动删除）
		// 第四个参数为当所有消费者客户端连接断开时是否自动删除队列
		// 第五个参数为队列的其他参数
		
		// 5.从队列里接收消息
		System.out.println("Consumer Waiting received messages：");
		// 告诉服务器我们需要哪个channel里的消息，如果该channel里有消息，就会执行回调函数
		// DefaultConsumer表示consumer采取的是pull模式来消费消息
		com.rabbitmq.client.Consumer consumer = new DefaultConsumer(channel) {
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope,
                    AMQP.BasicProperties properties, byte[] body) throws IOException {
				String message = new String(body, "UTF-8");
				System.out.println("Customer received message： " + message);
			}
		};
		
		// 6.回复确认
		// 第一个参数表示队列名称
		// 第二个参数为是否自动回复（true表示是）
		// 第三个参数为消费者
		channel.basicConsume(QUEUE_NAME, true, consumer);
		
		// 7.关闭连接
//		channel.close();
//		connection.close();
	}

}
